package com.blood.modules.system.service.impl;

import cn.hutool.core.lang.Snowflake;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.blood.core.config.AudienceConfig;
import com.blood.core.config.mybatisplus.ICommonServiceImpl;
import com.blood.core.constant.RedisKey;
import com.blood.core.enums.PregnancyStatusEnum;
import com.blood.core.enums.StatusEnum;
import com.blood.core.po.SysUserInfo;
import com.blood.core.resp.GlobalResultStatus;
import com.blood.core.resp.PageResult;
import com.blood.core.resp.ResponseResult;
import com.blood.core.resp.TokenResp;
import com.blood.core.util.ObjectAssertUtil;
import com.blood.core.util.bean.BeanUtil;
import com.blood.core.util.bean.ListUtils;
import com.blood.core.util.http.RequestTheadUtils;
import com.blood.core.util.token.TokenService;
import com.blood.modules.pregnancy.mapper.PregnancyUserMapper;
import com.blood.modules.pregnancy.model.PregnancyUser;
import com.blood.modules.system.dto.req.*;
import com.blood.modules.system.dto.resp.ResetPasswordResp;
import com.blood.modules.system.dto.resp.SysUserInfoResp;
import com.blood.modules.system.dto.resp.SysUserPageResp;
import com.blood.modules.system.mapper.SysUserMapper;
import com.blood.modules.system.model.SysOrgSchema;
import com.blood.modules.system.model.SysUser;
import com.blood.modules.system.service.ISysOrgSchemaService;
import com.blood.modules.system.service.ISysUserService;
import com.blood.redis.config.RedisUtil;
import com.sun.org.apache.regexp.internal.RE;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;


/**
 * 系统用户Service业务层处理
 *
 * @author daoren
 * @date 2022-05-12 09:14:48
 */
@Service
public class SysUserServiceImpl extends ICommonServiceImpl<SysUserMapper, SysUser> implements ISysUserService {
    @Autowired
    private Snowflake snowFlake;

    @Autowired
    private TokenService tokenService;

    @Autowired
    private ISysOrgSchemaService sysOrgSchemaService;
    @Autowired
    private PregnancyUserMapper pregnancyUserMapper;

    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private AudienceConfig audienceConfig;

    @Override
    public SysUser findByLoginName(String loginName) {
        return baseMapper.selectOne(
                new QueryWrapper<SysUser>()
                        .lambda()
                        .eq(SysUser::getPhone, loginName)
                        .eq(SysUser::isDeleteFlag, false));
    }

    @Override
    public ResponseResult<TokenResp> accountLogin(SysUserLoginReq req) {
        SysUser sysUser = this.findByLoginName(req.getLoginName());
        ObjectAssertUtil.objectIsNull(sysUser, "用户不存在!");
        ObjectAssertUtil.isBoolean(!sysUser.getPassword().equals(DigestUtils.md5Hex(req.getPassword())), "密码错误!");
        ObjectAssertUtil.isBoolean(sysUser.getStatus().equals(StatusEnum.DIS_ENABLE.getValue()), "账号已冻结!");
        ObjectAssertUtil.isBoolean(sysUser.getStatus().equals(StatusEnum.QUIT.getValue()), "员工已离职，不可登录!");
        TokenResp token = tokenService.getToken(sysUser.getId(), RequestTheadUtils.getPlatform());
        token.setUserName(sysUser.getUserName());
        //缓存登录信息
        cacheUserInfo(sysUser);
        return GlobalResultStatus.SUCCESS.toResult().response(token);
    }

    @Override
    public ResponseResult<PageResult<SysUserPageResp>> pageList(SysUserPageReq req) {
        PageResult<SysUserPageResp> pageResult = PageResult.create(req.getPageNo(), req.getPageSize());
        LambdaQueryWrapper<SysUser> qw = new LambdaQueryWrapper<>();
        if (StringUtils.isNotBlank(req.getPhone())) {
            qw.like(SysUser::getPhone, req.getPhone());
        }
        if (StringUtils.isNotBlank(req.getUserName())) {
            qw.like(SysUser::getUserName, req.getUserName());
        }

        if (StringUtils.isNotBlank(req.getRole())) {
            qw.eq(SysUser::getRole, req.getRole());
        }
        if (StringUtils.isNotBlank(req.getHospitalId())) {
            qw.eq(SysUser::getHospitalId, req.getHospitalId());
        }
        if (StringUtils.isNotBlank(req.getDepartId())) {
            qw.eq(SysUser::getDepartId, req.getDepartId());
        }
        if (null != req.getStatus()) {
            qw.eq(SysUser::getStatus, req.getStatus());
        }
        qw.orderByDesc(SysUser::getCreateTime);

        IPage<SysUser> iPage = baseMapper.selectPage(new Page<>(req.getPageNo(), req.getPageSize()), qw);
        if (iPage.getRecords().size() > 0) {
            List<PregnancyUser> userList = pregnancyUserMapper.selectList(new QueryWrapper<PregnancyUser>()
                    .select("count(id) as number ,create_by")
                    .lambda()
                    .in(PregnancyUser::getCreateBy, iPage.getRecords().stream().map(m -> m.getId()).collect(Collectors.toList()))
                    .eq(PregnancyUser::isDeleteFlag, false)
                    .groupBy(PregnancyUser::getCreateBy));
            ArrayList<SysUserPageResp> resps = new ArrayList<>(iPage.getRecords().size());
            for (SysUser record : iPage.getRecords()) {
                SysUserPageResp resp = new SysUserPageResp();
                BeanUtil.copyProperties(record, resp);
                resp.setNumber(userList.stream()
                        .filter(f -> f.getCreateBy().equals(record.getId()))
                        .findFirst()
                        .orElse(new PregnancyUser())
                        .getNumber());
                resps.add(resp);
            }
            return GlobalResultStatus.SUCCESS.toResult().response(pageResult.data(iPage.getTotal(), resps));
        }
        return GlobalResultStatus.SUCCESS.toResult().response(pageResult.data(0, Collections.emptyList()));
    }

    @Override
    public List<SysUser> queryList(SysUserReq req) {
        LambdaQueryWrapper<SysUser> lambda = new QueryWrapper<SysUser>().lambda();
        if (StringUtils.isNotBlank(req.getRole())) {
            lambda.eq(SysUser::getRole, req.getRole());
        }
        if (StringUtils.isNotBlank(req.getEmpNo())) {
            lambda.like(SysUser::getEmpNo, req.getEmpNo());
        }
        lambda.eq(SysUser::getHospitalId, RequestTheadUtils.getHospitalId())
                .eq(SysUser::getStatus, StatusEnum.ENABLE.getValue())
                .eq(SysUser::isDeleteFlag, false);
        return baseMapper.selectList(lambda);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult<Void> saveInfo(SysUserSaveReq req) {
        SysUser queryLoginName = this.findByLoginName(req.getPhone());
        ObjectAssertUtil.objectIsNotNull(queryLoginName, "登录用户已存在！");
        SysUser saveInfo = new SysUser();
        BeanUtil.copyProperties(req, saveInfo);

        setOrgInfo(req, saveInfo);

        String id = snowFlake.nextIdStr();
        saveInfo.setId(id);
        ObjectAssertUtil.isBoolean(req.getPhone().length() < 11, "联系电话有误！");
        saveInfo.setPassword(DigestUtils.md5Hex(req.getPhone().substring(5, 11)));
        saveInfo.setCreateBy(RequestTheadUtils.getUserId());
        saveInfo.setOrgId(RequestTheadUtils.getOrgId());
        baseMapper.insert(saveInfo);
        return GlobalResultStatus.SUCCESS.toResult().responseEmptyBody();
    }

    /**
     * 设置组织信息
     *
     * @param req
     * @param saveInfo
     */
    private void setOrgInfo(SysUserSaveReq req, SysUser saveInfo) {
        ArrayList<String> idList = new ArrayList<>(2);
        idList.add(req.getHospitalId());
        idList.add(req.getDepartId());
        List<SysOrgSchema> schemaList = sysOrgSchemaService.queryList(idList);
        SysOrgSchema hospitalInfo = schemaList.stream().filter(f -> "0".equals(f.getParentId()) && f.getId().equals(req.getHospitalId())).findFirst().orElse(null);
        ObjectAssertUtil.objectIsNull(hospitalInfo, "医院信息不存在！");
        saveInfo.setHospitalName(hospitalInfo.getHospitalName());
        SysOrgSchema departInfo = schemaList.stream().filter(f -> !"0".equals(f.getParentId()) && f.getId().equals(req.getDepartId())).findFirst().orElse(null);
        ObjectAssertUtil.objectIsNull(departInfo, "科室信息不存在！");
        saveInfo.setDepartName(departInfo.getDepartName());
    }


    private void cacheUserInfo(SysUser req) {
        SysUserInfo sysUserInfo = new SysUserInfo();
        sysUserInfo.setUserId(req.getId());
        sysUserInfo.setStatus(req.getStatus());
        sysUserInfo.setOrgId(req.getDepartId());
        sysUserInfo.setRole(req.getRole());
        sysUserInfo.setDepartId(req.getDepartId());
        sysUserInfo.setHospitalId(req.getHospitalId());
        redisUtil.set(RedisKey.USER_INFO.concat(req.getId()), sysUserInfo, Long.valueOf(audienceConfig.getExpiresDay() * 60 * 60 * 24));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult<Void> updateInfo(SysUserSaveReq req) {
        SysUser queryInfo = super.findById(req.getId());
        ObjectAssertUtil.objectIsNull(queryInfo, "未获取到详细信息!");
        if (!queryInfo.getPhone().equals(req.getPhone())) {
            SysUser queryLoginName = this.findByLoginName(req.getPhone());
            ObjectAssertUtil.objectIsNotNull(queryLoginName, "登录用户已存在！");
        }
        ObjectAssertUtil.isBoolean(req.getPhone().length() < 11, "联系电话有误！");
        BeanUtil.copyProperties(req, queryInfo);
        setOrgInfo(req, queryInfo);
        queryInfo.setUpdateBy(RequestTheadUtils.getUserId());
        baseMapper.updateById(queryInfo);
        cacheUserInfo(queryInfo);
        return GlobalResultStatus.SUCCESS.toResult().responseEmptyBody();
    }

    @Override
    public ResponseResult<Void> updateStatus(String id, Integer status) {
        SysUser queryInfo = super.findById(id);
        ObjectAssertUtil.objectIsNull(queryInfo, "用户不存在!");
        queryInfo.setStatus(status);
        queryInfo.setUpdateBy(RequestTheadUtils.getUserId());
        baseMapper.updateById(queryInfo);
        //缓存登录信息
        cacheUserInfo(queryInfo);
        return GlobalResultStatus.SUCCESS.toResult().responseEmptyBody();
    }

    @Override
    public ResponseResult<SysUserInfoResp> findDetailById(String id) {
        SysUser queryInfo = super.findById(id);
        ObjectAssertUtil.objectIsNull(queryInfo, "详细信息不存在!");
        return GlobalResultStatus.SUCCESS.toResult().response(BeanUtil.copyProperties(queryInfo, SysUserInfoResp.class));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult<ResetPasswordResp> resetPassword(String userId) {
        SysUser queryInfo = getSysUser(userId);
        String password = queryInfo.getPhone().substring(5, 11);
        queryInfo.setPassword(DigestUtils.md5Hex(password));
        queryInfo.setUpdateBy(RequestTheadUtils.getUserId());
        baseMapper.updateById(queryInfo);
        ResetPasswordResp resp = new ResetPasswordResp();
        resp.setLoginName(queryInfo.getPhone());
        resp.setUserName(queryInfo.getUserName());
        resp.setPassword(password);
        return GlobalResultStatus.SUCCESS.toResult().response(resp);
    }

    private SysUser getSysUser(String userId) {
        SysUser queryInfo = baseMapper.selectOne(new QueryWrapper<SysUser>().lambda()
                .eq(SysUser::getId, userId)
                .eq(SysUser::isDeleteFlag, false));
        ObjectAssertUtil.objectIsNull(queryInfo, "该用户账信息不存在！");
        return queryInfo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult<Void> updatePassword(SysUpdatePasswordReq req) {
        SysUser queryInfo = getSysUser(req.getId());
        ObjectAssertUtil.isBoolean(!queryInfo.getPassword().equals(DigestUtils.md5Hex(req.getOldPassword())), "旧密码错误");
        queryInfo.setPassword(DigestUtils.md5Hex(req.getNewPassword()));
        queryInfo.setUpdateBy(RequestTheadUtils.getUserId());
        baseMapper.updateById(queryInfo);
        return GlobalResultStatus.SUCCESS.toResult().responseEmptyBody();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult<Void> deleted(String id) {
        SysUser queryInfo = getSysUser(id);
        //有未完结的孕妇不可删除
        PregnancyUser pregnancyUser = pregnancyUserMapper.selectOne(new LambdaQueryWrapper<PregnancyUser>()
                .ne(PregnancyUser::getStatus, PregnancyStatusEnum.DISCHARGED.getValue())
                .and(wrapper -> wrapper.eq(PregnancyUser::getDoctorId, id)
                        .or().eq(PregnancyUser::getMidwifeId, id)
                        .or().eq(PregnancyUser::getNurseId, id))
                .last("limit 1")
        );
        ObjectAssertUtil.objectIsNotNull(pregnancyUser, "该账号存在关联未出院孕妇，不可删除！");
        queryInfo.setUpdateBy(RequestTheadUtils.getOrgId());
        queryInfo.setDeleteFlag(true);
        baseMapper.updateById(queryInfo);
        //清除缓存
        redisUtil.remove(RedisKey.USER_INFO.concat(queryInfo.getId()));
        return GlobalResultStatus.SUCCESS.toResult().responseEmptyBody();
    }
}
